Skip to content

perf(napi): cache resolved namespace members - #27

Merged
triniwiz merged 1 commit into
mainfrom
perf/napi-namespace-cache
Oct 17, 2026
Merged

triniwiz merged 1 commit into
mainfrom
perf/napi-namespace-cache

Conversation

@triniwiz

Copy link
Copy Markdown
Member

Summary

On the napi engines (Node, QuickJS, Hermes, JSC), namespace objects were Proxies whose get trap resolved metadata and built a new namespace, constructor or enum object on every access. Each level cost several microseconds, and Windows.Foundation === Windows.Foundation was false.

Now a namespace is a plain object whose prototype is the resolving Proxy. The first access to a name resolves it and defines it on the object as a read-only, non-enumerable, non-configurable own property (napi_define_properties). Later reads find the own property and never reach the Proxy, so the engine can cache them like any other property. __typeName__ is an own property from the start.

This is the napi counterpart of the classic change in #26.

Performance

Lookup Node before Node after QuickJS before QuickJS after
Windows.Foundation 4460 ns 12 ns 4300 ns 80 ns
Windows.Foundation.Uri 4022 ns 18 ns
Windows.UI.Xaml.Controls.Button 11613 ns 14 ns 12070 ns 420 ns
Windows.UI.Xaml.Visibility.Collapsed 11956 ns 10 ns

For reference, the same four-property chain on a plain JS object costs about 110–210 ns on QuickJS, so the remaining QuickJS cost is the interpreter. Node RSS after the benchmark dropped from 300 MB to 50 MB.

Behaviour changes

  • Namespace and enum objects keep their identity (Windows.Data.Json === Windows.Data.Json).
  • Assigning to a resolved name is ignored, and throws in strict mode. Names not in metadata can still be assigned.
  • Object.keys(namespace) stays empty.

Testing

  • windows-napi: npm test passes 406/406, plus new identity/read-only checks in ns-proxy-test.js (42/42).
  • QuickJS standalone host: packages/test/interop-check.js passes 22/22. Identity, own read-only properties, enums and construction checked in a script.
  • Hermes and JSC hosts not run; they share this code path.

Note: ColorHelper.ToDisplayName crash

Investigated and not a runtime bug. Small structs passed by value marshal correctly on both engines: new Windows.UI.Input.Inking.InkPoint({X:1.5,Y:2.5}, 0.5).Position round-trips exactly. The crash is a null dereference inside Windows.UI.Xaml.dll. ColorHelper ships in the XAML metadata, and the C# SDK doesn't even project it outside XAML/UWP apps, so it needs a running XAML app.

@coderabbitai

coderabbitai Bot commented Oct 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7a4d7c41-0574-47d0-998e-321fdcd1dfee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@triniwiz
triniwiz merged commit 2bbd057 into main Oct 17, 2026
4 checks passed
@triniwiz
triniwiz deleted the perf/napi-namespace-cache branch October 17, 2026 08:21
Namespace objects were Proxies whose get trap resolved metadata and
built a new namespace/ctor/enum object on every access
(`Windows.Foundation !== Windows.Foundation`).

A namespace is now a plain object whose prototype is the resolving
Proxy. A resolved name is defined on the object as a read-only,
non-enumerable own property, so later reads never reach the Proxy.

- Node: Windows.Foundation 4460 -> 12 ns,
  Windows.UI.Xaml.Controls.Button 11613 -> 14 ns
- QuickJS: Windows.Foundation 4300 -> 80 ns, Button 12070 -> 420 ns
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant